home *** CD-ROM | disk | FTP | other *** search
/ Programming Sound Cards / Programming Sound Cards.iso / sound_06 / play.c < prev    next >
Text File  |  1995-01-01  |  10KB  |  429 lines

  1. /*
  2.     PLAY.C
  3.  
  4.     29-jun-88, Marc Savary, Ad Lib Inc.
  5.  
  6.     Demo file to play the AdLib MIDI music file ( *.MUS) with the *.SND
  7.     timbre bank file.
  8.     This simple driver use the PC's timer-0 for timing. (see TIMER.ASM )
  9.  
  10.     See "convert.c" for *.MUS file structure.
  11.  
  12.     This file and the file BANK.C (timbre bank manager) MUST BE compiled
  13.     WITHOUT stack overflow check. (-v option of Lattice C Compiler,
  14.     -Gs for Microsoft)
  15.  
  16.     If compiling with Lattice, 'LATTICE' must be defined for this file
  17.     and BANK.C.
  18.  
  19.     With Microsoft, use the following ('MICROSOFT' must be defined for
  20.     this file and BANK.C):
  21.       masm timer.asm
  22.       cl -DMICROSOFT -AS -J -Zi -Zp1 -Ox -Gs -c play.c bank.c adlib.c
  23.       link play.obj adlib.obj bank.obj timer.obj
  24.  
  25. */
  26.  
  27. #include <stdio.h>
  28. #include <fcntl.h>
  29.  
  30. #include "convert.h"
  31. #include "bank.h"
  32.  
  33. #ifdef MICROSOFT
  34. #define UNSIGNED_CHAR unsigned char
  35. #endif
  36. #ifdef LATTICE
  37. #define UNSIGNED_CHAR char
  38. #endif
  39.  
  40. BankPtr    bank;                    /* pointer to instrument bank */
  41. char *        musPtr;                    /* pointer to first data byte of melody */
  42. struct        MusHeader * headPtr;    /* pointer to header of .MUS file */
  43. char        musRunning;                /* != 0 if music is playing */
  44. UNSIGNED_CHAR status;                                 /* running status byte */
  45. char        volume[ NR_VOICES];        /* actual volume of all voices */
  46.  
  47. long        tickCount;                /* time counter, for information only */
  48. unsigned    delay;                    /* length of last delay */
  49.  
  50. #ifdef LATTICE
  51. extern char * getmem();
  52. extern int allmem();
  53. extern int rlsmem();
  54. #endif
  55.  
  56. #ifdef MICROSOFT
  57. #include  <malloc.h>
  58. #include  <string.h>
  59. #define  rlsmem(x,y)    free(x)
  60. #define  getmem(x)      malloc(x)
  61. #define  setmem(x,y,z)  memset(x,z,y)
  62. #define  movmem(x,y,z)  memmove(y,x,z)
  63. #define  max(x,y)       ((x > y) ? x:y)
  64. #endif
  65.  
  66.  
  67. /*
  68.     Simple demonstration.
  69.  
  70.     Syntax:     play <musfile.mus> <bankfile.snd>
  71. */
  72. main( argc, argv)
  73.     int argc;
  74.     char * argv[];
  75.     {
  76.     struct MusHeader mH;
  77.     int meloFile;
  78.     char * music;
  79.     unsigned len;
  80.     BankPtr theBank;
  81.  
  82.     if( argc < 3) {
  83.         fprintf( stderr, "\nUSE: play <musfile.mus> <bankfile.snd>");
  84.         exit( 1);
  85.         }
  86.  
  87.     /* Perform some initialisations ... */
  88.     Init();
  89.  
  90.     if( NULL == ( theBank = OpenBank( argv[ 2], 0))) {
  91.         fprintf( stderr, "\nUnable to open timbre bank file '%s'.", argv[ 2]);
  92.         Terminate();
  93.         exit( 1);
  94.         }
  95.     if( !LoadBank( theBank)) {
  96.         fprintf( stderr, "\nError while reading timbre bank.");
  97.         Terminate();
  98.         exit( 1);
  99.         }
  100.     meloFile = open( argv[ 1], O_RDONLY + O_RAW);
  101.     if( -1 == meloFile) {
  102.         fprintf( stderr, "\nUnable to open music file '%s'.", argv[ 1]);
  103.         Terminate();
  104.         exit( 1);
  105.         }
  106.  
  107.     /* read the music file's header: */
  108.     read( meloFile, &mH, sizeof( struct MusHeader));
  109.     len = mH.dataSize;
  110.     music = (char *) getmem( (unsigned) len);
  111.     if( music == NULL) {
  112.         fprintf( stderr, "\nMemory allocation error.");
  113.         exit( 1);
  114.         }
  115.  
  116.     /* load all the data in memory: */
  117.     read( meloFile, music, len);
  118.  
  119.     /* Start playing: */
  120.     StartMelo( &mH, music, len, theBank);
  121.  
  122.     /* wait until end.... */
  123.     WaitEndMelo();
  124.  
  125.     /* uninstall the clock driver: */
  126.     Terminate();
  127.  
  128.     rlsmem( music, len);
  129.     CloseBank( theBank);
  130.     }    /* main() */
  131.  
  132.  
  133. /*
  134.     Wait until the end of melody ( musRunning == 0)
  135. */
  136. WaitEndMelo()
  137.     {
  138.     static unsigned measure = 0, beat = 0;
  139.     unsigned m, b, c, i;
  140.  
  141. /*    cprintf( "\nPress ESC key to stop");    */
  142.     while( musRunning) {
  143.         if( kbhit()) {
  144.             c = getch();
  145.             if( c == 0x1b)
  146.                 StopMelo();
  147.             }
  148. #ifdef DEBUG
  149.         m = tickCount / (headPtr->beatMeasure * headPtr->tickBeat);
  150.         b = tickCount / headPtr->tickBeat;
  151.         if( m != measure) {
  152.             printf( "\nMeasure: %03d ", m);
  153.             measure = m;
  154.             }
  155.         if( b != beat) {
  156.             printf( "+ ");
  157.             beat = b;
  158.             }
  159. #endif
  160.         }
  161.     }    /* WaitEndMelo() */
  162.  
  163.  
  164. /*
  165.     Initialize the driver.
  166. */
  167. Init()
  168.     {
  169.     /* initalize the low-level sound-driver: */
  170.     if( !SoundColdInit( 0x388)) {
  171.         printf( "\nAdlib board not found!");
  172.         exit( 1);
  173.         }
  174.  
  175.     /* allocate all the memory available:*/
  176. #ifdef LATTICE
  177.     allmem();
  178. #endif
  179.     /* install the clock driver: */
  180.     Clk_install();
  181.     }
  182.  
  183.  
  184. /*
  185.     Uninstall the clock driver ...
  186. */
  187. Terminate()
  188.     {
  189.     Clk_uninstall();
  190.     }
  191.  
  192.  
  193. /*
  194.     Start playing a melody. Set some global pointers for the interrupt
  195.     routine. Set the tempo, sound mode & pitch bend range.
  196.     Reset volume of each voice. Start the clock driver with the first
  197.     delay ( >= 1)
  198. */
  199. StartMelo( header, data, len, timBank)
  200.     struct MusHeader * header;    /* pointer to header struc. of music file */
  201.     char * data;            /* pointer to music data */
  202.     unsigned len;            /* size of data */
  203.     BankPtr timBank;        /* bank of timbres */
  204.     {
  205.     int i;
  206.  
  207.     musPtr = data;
  208.     headPtr = header;
  209.     bank = timBank;
  210.     tickCount = 0;
  211.     for( i = 0; i < NR_VOICES; i++)
  212.         volume[ i] = 0;
  213.  
  214.     SetMode( header->soundMode);
  215.     SetPitchRange( header->pitchBRange);
  216.     SetTempo( header->basicTempo, header->tickBeat);
  217.  
  218.     StartTimeOut( 0);
  219.     delay = *musPtr++;
  220.     musRunning = 1;
  221.     /* NEVER START COUNT-DOWN WITH 0, since 0 means MAXIMUM delay!!! */
  222.     StartTimeOut( max( delay, 1));
  223.     }   /* StartMelo() */
  224.  
  225.  
  226. /*
  227.     Stop playing the melody. Send note-off to all voices and reset
  228.     the clock frequency to nominal ( 18.2 Hz).
  229. */
  230. StopMelo()
  231.     {
  232.     int i;
  233.  
  234.     musRunning = 0;
  235.     for( i = 0; i < NR_VOICES; i++)
  236.         NoteOff( i);
  237.     SetTempo( 0, 1);
  238.     }    /* StopMelo() */
  239.  
  240.  
  241. /*
  242.     Change the tempo.
  243.  
  244.     Reload the timer-0 with the proper divider for generating
  245.     the appropriate frequency.
  246.  
  247.     If tempo is zero, reprogram the counter for 18.2 Hz.
  248. */
  249. SetTempo( tempo, tickBeat)
  250.     unsigned tempo;                /* beats per minute */
  251.     unsigned tickBeat;            /* ticks per beat */
  252.     {
  253.     long t1;
  254.     unsigned freq;
  255.     unsigned low, high, flags, count;
  256.  
  257.     t1 = tickBeat * (long)tempo;
  258.     freq = t1 /60;                /* interrupt rate needed */
  259.  
  260.     if( !freq)
  261.         count = 0;
  262.     else {
  263.         /* make sure that frequency is >= 19 Hz, since counter min. output
  264.             frequency is 18.2 Hz: */
  265.         freq = freq < 19 ? 19 : freq;
  266.         /* compute counter divider: */
  267.         count = (1193180 /(long)freq);
  268.         }
  269.     /* and set the counter: */
  270.     SetClkRate( count);
  271.     }   /* SetTempo() */
  272.  
  273.  
  274.  
  275. /*
  276.     Interrupt routine. Called by low-level clock driver when
  277.     the delay count has expired.
  278.  
  279.     'musPtr' always points to an OVERFLOW BYTE or to the first byte AFTER
  280.     the timing byte.
  281.  
  282.     When this routine is called, the active SS ( stack segment) is not
  283.     the original of the application, so take care. 
  284.     This routine, and all others called by, must be compiled
  285.     without stack-overflow checking, since the SS has changed!!!
  286.     
  287.     Return to caller the number of clock ticks to wait for before
  288.     the next call.
  289. */
  290. unsigned TimeOut()
  291.     {
  292.     unsigned pitch, tempo, haut, vol;
  293.     UNSIGNED_CHAR newStatus;
  294.     int timbreDef[ TIMBRE_DEF_LEN], timbre;
  295.     int comm, id, integer, frac, voice = 1;
  296.  
  297.     if( ! musRunning)
  298.         /* Music has not started or has been stopped, so wait the minimum delay ... */
  299.         return 1;
  300.  
  301.     tickCount += delay;
  302.     do {
  303.         newStatus = *musPtr;
  304.         if( newStatus == OVERFLOW_BYTE) {
  305.             /* timing overflow ... */
  306.             musPtr++;
  307.             delay = OVERFLOW_BYTE;
  308.             break;
  309.             }
  310.  
  311.         else if( newStatus == STOP_BYTE) {
  312.             StopMelo();
  313.             return 0;       /* maximum delay ... */
  314.             }
  315.         else if( newStatus == SYSTEM_XOR_BYTE) {
  316.             /*
  317.             non-standard... this is a tempo multiplier:
  318.             data format: <F0> <7F> <00> <integer> <frac> <F7>
  319.             tempo = basicTempo * integerPart + basicTempo * fractionPart/128
  320.             */
  321.             musPtr++;
  322.             id = *musPtr++;
  323.             comm = *musPtr++;
  324.             if( id != ADLIB_CTRL_BYTE || comm != TEMPO_CTRL_BYTE) {
  325.                 /* unknown format ... skip all the XOR message */
  326.                 musPtr -= 2;
  327.                 while( *musPtr++ != EOX_BYTE)
  328.                     ;
  329.                 }
  330.             else {
  331.                 integer = *musPtr++;
  332.                 frac = *musPtr++;
  333.                 tempo = headPtr->basicTempo;
  334.                 tempo = tempo * integer + (unsigned)(((long)tempo * frac) >> 7);
  335.                 SetTempo( tempo, headPtr->tickBeat);
  336.                 musPtr++;       /* skip EOX_BYTE */
  337.                 }
  338.             delay = *musPtr++;
  339.             }
  340.         else {
  341.             if( newStatus >= 0x80) {
  342.                 musPtr++;
  343.                 status = newStatus;
  344.                 }
  345.             voice = (int) (status & 0x0f);
  346.  
  347.             switch( status & 0xf0) {
  348.                 case NOTE_ON_BYTE:
  349.                     haut = *musPtr++;
  350.                     vol = *musPtr++;
  351.                     if( ! vol) {
  352.                         NoteOff( voice);
  353.                         }
  354.                     else {
  355.                         if( vol != volume[ voice]) {
  356.                             SetVoiceVolume( voice, vol);
  357.                             volume[ voice] = vol;
  358.                             }
  359.                         NoteOn( voice, haut);
  360.                         }
  361.                     break;
  362.  
  363.                 case NOTE_OFF_BYTE:
  364.                     musPtr += 2;
  365.                     NoteOff( voice);
  366.                     break;
  367.  
  368.                 case AFTER_TOUCH_BYTE:
  369.                     SetVoiceVolume( voice, *musPtr++);
  370.                     break;
  371.  
  372.                 case PROG_CHANGE_BYTE:
  373.                     timbre = *musPtr++;
  374.                     if( GetTimbre( "", &timbre, timbreDef, bank)) {
  375.                         SetVoiceTimbre( voice, timbreDef);
  376.                         }
  377.                     else
  378.                         cprintf( "\nTimbre not found: %d", timbre);
  379.                     break;
  380.  
  381.                 case PITCH_BEND_BYTE:
  382.                     pitch = *musPtr++;
  383.                     pitch += (unsigned)(*musPtr++) << 7;
  384.                     SetVoicePitch( voice, pitch);
  385.                     break;
  386.  
  387.                 case CONTROL_CHANGE_BYTE:
  388.                     /* not implemented ... */
  389.                     musPtr += 2;
  390.                     break;
  391.  
  392.                 case CHANNEL_PRESSURE_BYTE:
  393.                     /* not implemented ... */
  394.                     musPtr++;
  395.                     break;
  396.  
  397.                 default:
  398.                     cprintf( "\nBad MIDI status byte: %d", status);
  399.                     SkipToTiming();
  400.                     break;
  401.                 }
  402.  
  403.             delay = *musPtr++;
  404.             }
  405.         } while( delay == 0);
  406.  
  407.     if( delay == OVERFLOW_BYTE) {
  408.         delay = OVERFLOW;
  409.         if( *musPtr != OVERFLOW_BYTE)
  410.             delay += *musPtr++;
  411.         }
  412.     return delay;
  413. }
  414.  
  415.  
  416. /*
  417.     A bad status byte ( or unimplemented MIDI command) has been encontered.
  418.     Skip bytes until next timing byte followed by status byte.
  419. */
  420. static SkipToTiming()
  421.     {
  422.     while( *musPtr < 0x80)
  423.         musPtr++;
  424.     if( *musPtr != OVERFLOW_BYTE)
  425.         musPtr--;
  426.     }    /* SkipToTiming() */
  427.  
  428.  
  429.